package xyz.riceball.start.handler;

import cn.hutool.http.HttpStatus;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;
import xyz.riceball.framework.core.bean.ApiR;
import xyz.riceball.framework.core.exception.RiceBallBizErrorException;
import xyz.riceball.framework.core.exception.RiceBallBizInfoException;
import xyz.riceball.framework.core.exception.RiceBallBizWarnException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Map;

/**
 * <p>
 * 全局的异常拦截处理器
 * </p>
 *
 * @author xiaovcloud
 * @since 2022/5/2 15:58
 */
@RestControllerAdvice
@Slf4j
public class RiceBallExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ApiR<String> defaultErrorHandler(HttpServletRequest req, HttpServletResponse resp, Exception e) {
        String requestURI = "[" + req.getMethod() + "] " + req.getRequestURI();
        //404资源直接不打印，直接返回
        if (e instanceof NoHandlerFoundException) {
            resp.setStatus(HttpStatus.HTTP_NOT_FOUND);
            return ApiR.error(HttpStatus.HTTP_NOT_FOUND, "请求路径未找到", requestURI);
        }
        log.error("<<<===访问出错，开始输出日志===>>>");
        log.error("访问类型：{},访问的路径：{}", req.getMethod(), req.getRequestURL());
        StringBuilder builder = new StringBuilder("#");
        Map<String, String[]> parameterMap = req.getParameterMap();
        parameterMap.forEach((k, v) -> {
            builder.append(k).append(":").append(Arrays.toString(v)).append("#");
        });
        log.error("访问的参数：{}", builder);
        ApiR<String> result = null;
        //自己的业务逻辑错误
        if (e instanceof RiceBallBizErrorException) {
            result = ApiR.error(((RiceBallBizErrorException) e).getCode(), e.getMessage(), requestURI);
        }
        if (e instanceof RiceBallBizWarnException) {
            result = ApiR.warn(((RiceBallBizWarnException) e).getCode(), e.getMessage(), requestURI);
        }
        if (e instanceof RiceBallBizInfoException) {
            result = ApiR.info(((RiceBallBizInfoException) e).getCode(), e.getMessage(), requestURI);
        }
        //权限方面的错误
        if (e instanceof ExpiredJwtException) {
            result = ApiR.error(HttpStatus.HTTP_FORBIDDEN, "登录失效，请重新登录", requestURI);
        }

        //数据校验出现问题
        if (e instanceof BindException) {
            BindException ex = (BindException) e;
            result = ApiR.warn(HttpStatus.HTTP_INTERNAL_ERROR, ex.getBindingResult().getFieldErrors().get(0).getDefaultMessage(), req.getRequestURI());
        }

        if (e instanceof RedisSystemException) {
            result = ApiR.error(HttpStatus.HTTP_INTERNAL_ERROR, "缓存连接超时", requestURI);
        }

        //如果前面没有匹配到，则匹配通用的500错误
        if (result == null) {
            // result = ApiR.error(HttpStatus.HTTP_INTERNAL_ERROR, "服务器内部错误", requestURI);
            // 开发阶段，设置成系统的错误
            result = ApiR.error(HttpStatus.HTTP_INTERNAL_ERROR, e.getMessage(), requestURI);
        }
        resp.setStatus(result.getCode());
        log.error("状态码：{}", result.getCode());
        log.error("报错信息：{}", result.getMsg());
        log.error("<<<===异常信息栈开始打印===>>>", e);
        return result;
    }

}
